package br.com.pucrs.aa.environment;

import jason.environment.grid.Location;

import java.util.ArrayList;
import java.util.List;

import br.com.pucrs.aa.Stop;
import br.com.pucrs.aa.Street;
import br.com.pucrs.aa.StreetModel;
import br.com.pucrs.aa.TrafficIntensity;

/**
 * 
 * @author rmalvezzi
 *
 */
public abstract class StreetEnvironment implements StreetEnvironmentInteface {

	protected TrafficIntensity trafficIntensity;
	protected StreetModel model;
	protected List<Street> streets;

	public StreetEnvironment(TrafficIntensity trafficIntensity) {
		this.trafficIntensity = trafficIntensity;
		this.streets = new ArrayList<Street>();

		int nbCoordinators = this.getCoordinatorSize();
		int nbWalkers = this.getTotalWalkerSize(trafficIntensity);

		int gridHeight = (StreetEnvironmentInteface.N_OBSTACLES_PER_RECT * (nbCoordinators + 1)) + nbCoordinators * 2;
		this.model = new StreetModel(StreetEnvironmentInteface.GRID_WITH, gridHeight, nbWalkers + nbCoordinators);

		this.model.setNumberOfCoordinators(nbCoordinators);
		this.model.setNumberOfWalkers(nbWalkers);

		this.buildAndAssignStreets();
		this.startWalkerAgentsPosition();

		// Assign quadrants (delimit area) to the little blue agent
		for (int i = 0; i < nbCoordinators; i++) {
			this.model.assignLocationsToCoordinator(nbWalkers + i, this.getQuadrants(i + 1));
		}

		List<Stop> buildStopPosition = this.buildStopPosition(nbWalkers);
		this.model.addStops(buildStopPosition);
		for (Stop stop : buildStopPosition) {
			this.model.add(StreetModel.STOP, stop.getLocation().x, stop.getLocation().y);
		}

		this.buildObstacles(nbCoordinators, gridHeight);
	}

	private ArrayList<Location> getQuadrants(int crossing) {
		ArrayList<Location> quadrants = new ArrayList<Location>();
		quadrants.add(new Location(5, this.calculaPosicao(crossing)));
		quadrants.add(new Location(5, this.calculaPosicao(crossing) + 1));
		quadrants.add(new Location(6, this.calculaPosicao(crossing)));
		quadrants.add(new Location(6, this.calculaPosicao(crossing) + 1));
		return quadrants;
	}

	private Integer calculaPosicao(int crossing) {
		return StreetEnvironmentInteface.N_OBSTACLES_PER_RECT * crossing + (crossing - 1) * StreetEnvironmentInteface.SIZE_STREET;
	}

	private Integer getTotalWalkerSize(TrafficIntensity trafficIntensity) {
		switch (trafficIntensity) {
		case LOW:
			return this.getWalkerSize();
		case MEDIUM:
			return this.getWalkerSize() * 2;
		case HIGH:
			return this.getWalkerSize() * 3;
		}
		return 0;
	}

	public StreetModel getModel() {
		return this.model;
	}

	/**
	 * Add all obstacles (part of street that agents cannot walk) 
	 */
	public void buildObstacles(Integer nbCoordinators, Integer gridHeight) {
		int[] valoresY = new int[nbCoordinators * 2];
		for (int i = 0; i < nbCoordinators; i++) {
			Integer calculaPosicao = this.calculaPosicao(i + 1);
			valoresY[i * 2] = calculaPosicao;
			valoresY[i * 2 + 1] = calculaPosicao + 1;
		}
		int startX = 0;
		int startY = 0;
		for (int i = 0; i < nbCoordinators; i++) {
			for (int x = 0; x < StreetEnvironmentInteface.GRID_WITH; x++) {
				if (x == 5 || x == 6) { // street
					continue;
				}
				for (int y = 0; y < gridHeight; y++) {
					if (this.validaLista(valoresY, y)) { // street
						continue;
					}
					this.model.add(StreetModel.OBSTACLE, startX + x, startY + y);
				}
			}
		}
	}

	private boolean validaLista(int[] valoresY, int y) {
		for (int i : valoresY) {
			if (i == y) {
				return true;
			}
		}
		return false;
	}

}
